<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">




  
  
  
  

  
    
    
  

  
    
      
    

    
  

  

  

  
    
      
    

    
  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Monda:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT">










<meta name="description" content="内容 什么是WebSocket协议 为什么要用WebSocket 了解WebSocket WebkSocket相关API 完整例子  什么是WebSocket协议websocket是html5规范中的一部分，它借鉴了socket这种思想，为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时，它又是一种新的应用层协议，websocket协议是为了提供web应用程序和服务端全双工通信而专门">
<meta property="og:type" content="article">
<meta property="og:title" content="websocket学习">
<meta property="og:url" content="http://blog.xiaowuzi.info/2016/04/08/websocket学习/index.html">
<meta property="og:site_name" content="小武子博客">
<meta property="og:description" content="内容 什么是WebSocket协议 为什么要用WebSocket 了解WebSocket WebkSocket相关API 完整例子  什么是WebSocket协议websocket是html5规范中的一部分，它借鉴了socket这种思想，为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时，它又是一种新的应用层协议，websocket协议是为了提供web应用程序和服务端全双工通信而专门">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="http://blog.xiaowuzi.info/images/socket/561794-20180304120333594-1298253171.png">
<meta property="og:image" content="http://blog.xiaowuzi.info/images/socket/561794-20180304120403624-161670948.png">
<meta property="og:image" content="http://blog.xiaowuzi.info/images/socket/640.png">
<meta property="og:updated_time" content="2018-12-10T12:34:34.069Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="websocket学习">
<meta name="twitter:description" content="内容 什么是WebSocket协议 为什么要用WebSocket 了解WebSocket WebkSocket相关API 完整例子  什么是WebSocket协议websocket是html5规范中的一部分，它借鉴了socket这种思想，为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时，它又是一种新的应用层协议，websocket协议是为了提供web应用程序和服务端全双工通信而专门">
<meta name="twitter:image" content="http://blog.xiaowuzi.info/images/socket/561794-20180304120333594-1298253171.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://blog.xiaowuzi.info/2016/04/08/websocket学习/">





  <title>websocket学习 | 小武子博客</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">小武子博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br>
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br>
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br>
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://blog.xiaowuzi.info/2016/04/08/websocket学习/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Tony">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="小武子博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">websocket学习</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2016-04-08T11:31:01+08:00">
                2016-04-08
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/网络/" itemprop="url" rel="index">
                    <span itemprop="name">网络</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h3 id="内容"><a href="#内容" class="headerlink" title="内容"></a>内容</h3><ol>
<li>什么是WebSocket协议</li>
<li>为什么要用WebSocket</li>
<li>了解WebSocket</li>
<li>WebkSocket相关API</li>
<li>完整例子</li>
</ol>
<h3 id="什么是WebSocket协议"><a href="#什么是WebSocket协议" class="headerlink" title="什么是WebSocket协议"></a>什么是WebSocket协议</h3><p>websocket是html5规范中的一部分，它借鉴了socket这种思想，为web应用程序客户端和服务端之间提供了一种全双工通信机制。同时，它又是一种新的应用层协议，websocket协议是为了提供web应用程序和服务端全双工通信而专门制定的一种应用层协议，通常它表示ws://echo.websocket.org/?encoding=text HTTP/1.1，可以看到除了前面的协议名和http不同之外，它的表示地址就是传统的url地址。</p>
<h3 id="为什么要用WebSocket"><a href="#为什么要用WebSocket" class="headerlink" title="为什么要用WebSocket"></a>为什么要用WebSocket</h3><p><strong>1. 现有的HTTP的架构模式</strong><br>Http是客户端/服务器模式中请求-响应所用的协议，在这种模式中，客户端（一般是web浏览器）向服务器提交HTTP请求，服务器响应请求的资源。关于HTTP协议请点击<a href="http://blog.xiaowuzi.info/2016/04/07/http%E8%AF%A6%E8%A7%A3/">这里</a>。</p>
<p><strong>2. HTTP的特点</strong></p>
<p>HTTP是半双工协议，也就是说，在同一时刻流星只能单向流动，客户端向服务器发送请求，然后服务器响应请求。服务器不能主动推送数据给浏览器。当然这个http2已经支持了。</p>
<p>当初这么设计也是有原因的，假如服务器能主动推送数据给浏览器的话，那么浏览器很容易受到攻击，比如一些广告商会主动把一些广告信息强行的传输给客户端。</p>
<p>半双工的缺点是：效率非常低。</p>
<p><strong>3. 了解HTTP轮询，长轮询及存在的问题</strong></p>
<p>一般情况下，浏览器访问网页时，会向页面所在的服务器发送一个HTTP请求，Web服务器确认请求并向浏览器返回响应。但是像股价，实时新闻等到达浏览器</p>
<p>显示页面时已经过时了，如果用户想要得到最新的实时信息，他们就要不断的刷新页面，这种显然是不切实际的。<br><a id="more"></a><br><strong>轮询：</strong>轮询是通过浏览器定时的向web服务器发送http的get请求，服务器收到请求后，就把最新的数据发回给客户端，客户端得到数据后，将其显示出来，然后再定期的重复这一过程，虽然可以满足需求，但是存在一些缺点，比如某一段时间内web服务器没有更新的数据，但是浏览器仍然需要定时的发送Get请求过来询问，那么即浪费了带宽，又浪费了cpu的利用率。如图：</p>
<p><img src="/images/socket/561794-20180304120333594-1298253171.png" alt=""></p>
<p><strong>长轮询：</strong>客户端向服务器请求信息，并在设定的时间段内打开一个连接，服务器如果没有任何信息，会保持请求打开，直到有客户端可用的信息，或者直到指定的超时用完为止。这个时候，客户端会重新向服务器请求信息。长轮询也可以叫做comet或反向ajax。它会延长HTTP响应的完成，直到服务器有需要发送给客户端的内容，这种技术通常可以叫“挂起GET”或“搁置POST”</p>
<p>缺点是：<br>当信息量非常大的时候，长轮询相对于http轮询并没有明显的性能优势，因为客户端必须频繁地重连到服务器以读取新信息。造成网络的表现和常规轮询相同。</p>
<p>如图：</p>
<p><img src="/images/socket/561794-20180304120403624-161670948.png" alt=""></p>
<p>关于web端通信资料可以参考：<a href="http://www.52im.net/thread-336-1-1.html" target="_blank" rel="noopener">Web端即时通讯技术盘点：短轮询、Comet、Websocket、SSE</a></p>
<h3 id="了解WebSocket"><a href="#了解WebSocket" class="headerlink" title="了解WebSocket"></a>了解WebSocket</h3><p>WebSocket是一种全双工，双向，单套接字连接，使用websocket，http请求变成打开websocket的链接的单一请求，并且重用从客户端到服务器以及服务器到客户端的同一连接。</p>
<p>WebSocket减少了延迟，因为一旦建立起Websocket连接，服务器可以在消息可用时发送他们。和轮询不同的是：WebSocket只发出一个请求，服务器不需要等待来自客户端的请求，且客户端可以在任何时候向服务器端发送消息，和轮询相比的话，不管是否有可用消息，每隔一段时间都发送一个请求，单一请求大大减少了延迟。</p>
<p>如图：</p>
<p><img src="/images/socket/640.png" alt=""></p>
<p>其特点：</p>
<ol>
<li>握手阶段采用 HTTP 协议，默认端口是80和443</li>
<li>建立在TCP协议基础之上，和http协议同属于应用层</li>
<li>可以发送文本，也可以发送二进制数据</li>
<li>没有同源限制，客户端可以与任意服务器通信</li>
<li>协议标识符是ws（如果加密，为wss），如ws://localhost:8023</li>
</ol>
<p><strong>优点有如下：</strong></p>
<ol>
<li>WebSocket使实时通信更加有效。能节约带宽，CPU资源并减少延迟。</li>
<li>WebSocket使Web上客户端和服务器之间的通信变得更加的简单。</li>
<li>Websocket是一个底层网络协议，我们可以在它的基础之上构建其他的标准协议。</li>
<li>较少的控制开销。连接创建后，ws客户端、服务端进行数据交换时，协议控制的数据包头部较小。在不包含头部的情况下，服务端到客户端的包头只有2~10字节（取决于数据包长度），客户端到服务端的的话，需要加上额外的4字节的掩码。而HTTP协议每次通信都需要携带完整的头部。</li>
</ol>
<p><strong>WebSocket的应用场景？</strong></p>
<p>比如聊天，大型多人在线游戏，股票交易应用或实时新闻等。</p>
<h3 id="WebkSocket相关API"><a href="#WebkSocket相关API" class="headerlink" title="WebkSocket相关API"></a>WebkSocket相关API</h3><h4 id="客户端的API"><a href="#客户端的API" class="headerlink" title="客户端的API"></a>客户端的API</h4><p><strong>WebSocket构造函数</strong></p>
<p>通过调用WebSocket构造函数来创建一个WebSocket实例对象，建立客户端与服务器的连接。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const ws=new WebSocket(&apos;ws://localhost:8080&apos;);</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.readyState</strong></p>
<p><strong>readyState</strong>属性返回实例对象的当前状态，共有四种。</p>
<ul>
<li>CONNECTING：值为0，表示正在连接。</li>
<li>OPEN：值为1，表示连接成功，可以通信了。</li>
<li>CLOSING：值为2，表示连接正在关闭。</li>
<li>CLOSED：值为3，表示连接已经关闭，或者打开连接失败。</li>
</ul>
<p>示例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">switch (ws.readyState) &#123;</span><br><span class="line">  case WebSocket.CONNECTING:</span><br><span class="line">    // do something</span><br><span class="line">    break;</span><br><span class="line">  case WebSocket.OPEN:</span><br><span class="line">    // do something</span><br><span class="line">    break;</span><br><span class="line">  case WebSocket.CLOSING:</span><br><span class="line">    // do something</span><br><span class="line">    break;</span><br><span class="line">  case WebSocket.CLOSED:</span><br><span class="line">    // do something</span><br><span class="line">    break;</span><br><span class="line">  default:</span><br><span class="line">    // this never happens</span><br><span class="line">    break;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.onopen</strong></p>
<p>实例对象的<strong>onopen</strong>属性，用于指定连接成功后的回调函数。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ws.onopen=function()&#123;</span><br><span class="line">	ws.send(&apos;Hello Server!&apos;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果要指定多个回调函数，可以使用addEventListener方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ws.addEventListener(&apos;open&apos;, function (event) &#123;</span><br><span class="line">  ws.send(&apos;Hello Server!&apos;);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.onclose</strong></p>
<p>实例对象的<strong>onclose</strong>属性，用于指定连接关闭后的回调函数。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">ws.onclose = function(event) &#123;</span><br><span class="line">  var code = event.code;</span><br><span class="line">  var reason = event.reason;</span><br><span class="line">  var wasClean = event.wasClean;</span><br><span class="line">  // handle close event</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">ws.addEventListener(&quot;close&quot;, function(event) &#123;</span><br><span class="line">  var code = event.code;</span><br><span class="line">  var reason = event.reason;</span><br><span class="line">  var wasClean = event.wasClean;</span><br><span class="line">  // handle close event</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.onmessage</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">ws.onmessage = function(event) &#123;</span><br><span class="line">  var data = event.data;</span><br><span class="line">  // 处理数据</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">ws.addEventListener(&quot;message&quot;, function(event) &#123;</span><br><span class="line">  var data = event.data;</span><br><span class="line">  // 处理数据</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p>服务器数据可能是文本，也可能是二进制数据（blob对象或Arraybuffer对象）。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">ws.onmessage = function(event)&#123;</span><br><span class="line">  if(typeof event.data === String) &#123;</span><br><span class="line">    console.log(&quot;Received data string&quot;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  if(event.data instanceof ArrayBuffer)&#123;</span><br><span class="line">    var buffer = event.data;</span><br><span class="line">    console.log(&quot;Received arraybuffer&quot;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>除了动态判断收到的数据类型，也可以使用binaryType属性，显式指定收到的二进制数据类型。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">// 收到的是 blob 数据</span><br><span class="line">ws.binaryType = &quot;blob&quot;;</span><br><span class="line">ws.onmessage = function(e) &#123;</span><br><span class="line">  console.log(e.data.size);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 收到的是 ArrayBuffer 数据</span><br><span class="line">ws.binaryType = &quot;arraybuffer&quot;;</span><br><span class="line">ws.onmessage = function(e) &#123;</span><br><span class="line">  console.log(e.data.byteLength);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.send()</strong></p>
<p>实例对象的send()方法用于向服务器发送数据。</p>
<p>发送文本例子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ws.send(&apos;your message&apos;);</span><br></pre></td></tr></table></figure>
<p>发送Blob对象例子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var file = document</span><br><span class="line">  .querySelector(&apos;input[type=&quot;file&quot;]&apos;)</span><br><span class="line">  .files[0];</span><br><span class="line">ws.send(file);</span><br></pre></td></tr></table></figure>
<p>发送 ArrayBuffer 对象例子</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// Sending canvas ImageData as ArrayBuffer</span><br><span class="line">var img = canvas_context.getImageData(0, 0, 400, 320);</span><br><span class="line">var binary = new Uint8Array(img.data.length);</span><br><span class="line">for (var i = 0; i &lt; img.data.length; i++) &#123;</span><br><span class="line">  binary[i] = img.data[i];</span><br><span class="line">&#125;</span><br><span class="line">ws.send(binary.buffer);</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.bufferedAmount</strong></p>
<p>实例对象的bufferedAmount属性，表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">var data = new ArrayBuffer(10000000);</span><br><span class="line">socket.send(data);</span><br><span class="line"></span><br><span class="line">if (socket.bufferedAmount === 0) &#123;</span><br><span class="line">  // 发送完毕</span><br><span class="line">&#125; else &#123;</span><br><span class="line">  // 发送还没结束</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>webSocket.onerror</strong></p>
<p>实例对象的onerror属性，用于指定报错时的回调函数。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">socket.onerror = function(event) &#123;</span><br><span class="line">  // handle error event</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">socket.addEventListener(&quot;error&quot;, function(event) &#123;</span><br><span class="line">  // handle error event</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<h4 id="服务端的实现"><a href="#服务端的实现" class="headerlink" title="服务端的实现"></a>服务端的实现</h4><p>WebSocket 服务器的实现，可以查看维基百科的<a href="https://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations" target="_blank" rel="noopener">列表</a>。</p>
<p>常用的 Node 实现有以下三种。</p>
<ul>
<li>µWebSockets</li>
<li>Socket.IO</li>
<li>WebSocket-Node</li>
</ul>
<h3 id="完整例子"><a href="#完整例子" class="headerlink" title="完整例子"></a>完整例子</h3><p><strong>客户端代码</strong>client.html</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head lang=&quot;en&quot;&gt;</span><br><span class="line">    &lt;meta charset=&quot;UTF-8&quot;&gt;</span><br><span class="line">    &lt;title&gt;&lt;/title&gt;</span><br><span class="line">    &lt;style&gt;</span><br><span class="line">        *&#123;</span><br><span class="line">            margin: 0;</span><br><span class="line">            padding: 0;</span><br><span class="line">        &#125;</span><br><span class="line">        .message&#123;</span><br><span class="line">            width: 60%;</span><br><span class="line">            margin: 0 10px;</span><br><span class="line">            display: inline-block;</span><br><span class="line">            text-align: center;</span><br><span class="line">            height: 40px;</span><br><span class="line">            line-height: 40px;</span><br><span class="line">            font-size: 20px;</span><br><span class="line">            border-radius: 5px;</span><br><span class="line">            border: 1px solid #B3D33F;</span><br><span class="line">        &#125;</span><br><span class="line">        .form&#123;</span><br><span class="line">            width:100%;</span><br><span class="line">            position: fixed;</span><br><span class="line">            bottom: 300px;</span><br><span class="line">            left: 0;</span><br><span class="line">        &#125;</span><br><span class="line">        .connect&#123;</span><br><span class="line">            height: 40px;</span><br><span class="line">            vertical-align: top;</span><br><span class="line">            /* padding: 0; */</span><br><span class="line">            width: 80px;</span><br><span class="line">            font-size: 20px;</span><br><span class="line">            border-radius: 5px;</span><br><span class="line">            border: none;</span><br><span class="line">            background: #B3D33F;</span><br><span class="line">            color: #fff;</span><br><span class="line">        &#125;</span><br><span class="line">    &lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;ul id=&quot;content&quot;&gt;&lt;/ul&gt;</span><br><span class="line">&lt;form class=&quot;form&quot;&gt;</span><br><span class="line">&lt;input type=&quot;text&quot; placeholder=&quot;请输入发送的消息&quot; class=&quot;message&quot; id=&quot;message&quot;/&gt;</span><br><span class="line">&lt;input type=&quot;button&quot; value=&quot;发送&quot; id=&quot;send&quot; class=&quot;connect&quot;/&gt;</span><br><span class="line">&lt;input type=&quot;button&quot; value=&quot;连接&quot; id=&quot;connect&quot; class=&quot;connect&quot;/&gt;</span><br><span class="line">&lt;/form&gt;</span><br><span class="line">&lt;script&gt;&lt;/script&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure>
<p><strong>客户端js代码</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">var oUl=document.getElementById(&apos;content&apos;);</span><br><span class="line">    var oConnect=document.getElementById(&apos;connect&apos;);</span><br><span class="line">    var oSend=document.getElementById(&apos;send&apos;);</span><br><span class="line">    var oInput=document.getElementById(&apos;message&apos;);</span><br><span class="line">    var ws=null;</span><br><span class="line">    oConnect.onclick=function()&#123;</span><br><span class="line">        ws=new WebSocket(&apos;ws://localhost:5000&apos;);</span><br><span class="line">         ws.onopen=function()&#123;</span><br><span class="line">             oUl.innerHTML+=&quot;&lt;li&gt;客户端已连接&lt;/li&gt;&quot;;</span><br><span class="line">         &#125;</span><br><span class="line">        ws.onmessage=function(evt)&#123;</span><br><span class="line">            oUl.innerHTML+=&quot;&lt;li&gt;&quot;+evt.data+&quot;&lt;/li&gt;&quot;;</span><br><span class="line">        &#125;</span><br><span class="line">        ws.onclose=function()&#123;</span><br><span class="line">            oUl.innerHTML+=&quot;&lt;li&gt;客户端已断开连接&lt;/li&gt;&quot;;</span><br><span class="line">        &#125;;</span><br><span class="line">        ws.onerror=function(evt)&#123;</span><br><span class="line">            oUl.innerHTML+=&quot;&lt;li&gt;&quot;+evt.data+&quot;&lt;/li&gt;&quot;;</span><br><span class="line"> </span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;;</span><br><span class="line">    oSend.onclick=function()&#123;</span><br><span class="line">        if(ws)&#123;</span><br><span class="line">            ws.send(oInput.value);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p><strong>服务端代码</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">var app=require(&apos;http&apos;).createServer(handler);</span><br><span class="line">var ws=require(&apos;nodejs-websocket&apos;);</span><br><span class="line">var fs=require(&apos;fs&apos;);</span><br><span class="line">app.listen(80);</span><br><span class="line">function handler(req,res)&#123;</span><br><span class="line">    fs.readFile(__dirname+&apos;/client.html&apos;,function(err,data)&#123;</span><br><span class="line">        if(err)&#123;</span><br><span class="line">            res.writeHead(500);</span><br><span class="line">            return res.end(&apos;error &apos;);</span><br><span class="line">        &#125;</span><br><span class="line">        res.writeHead(200);</span><br><span class="line">        res.end(data);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line">var server=ws.createServer(function(conn)&#123;</span><br><span class="line">    console.log(&apos;new conneciton&apos;);</span><br><span class="line">    conn.on(&quot;text&quot;,function(str)&#123;</span><br><span class="line">        broadcast(server,str);</span><br><span class="line">    &#125;);</span><br><span class="line">    conn.on(&quot;close&quot;,function(code,reason)&#123;</span><br><span class="line">        console.log(&apos;connection closed&apos;);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;).listen(5000);</span><br><span class="line"> </span><br><span class="line">function broadcast(server, msg) &#123;</span><br><span class="line">    server.connections.forEach(function (conn) &#123;</span><br><span class="line">        conn.sendText(msg);</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>参考资料：</p>
<p><a href="http://www.ruanyifeng.com/blog/2017/05/websocket.html" target="_blank" rel="noopener">WebSocket 教程</a></p>
<p><a href="http://www.cnblogs.com/tugenhua0707/p/8504297.html" target="_blank" rel="noopener">WebSocket原理与实践(一)—基本原理</a></p>
      
    </div>
    
    
    

    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center">
  <div>Donate comment here</div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="/images/wechatpay.jpg" alt="Tony 微信支付">
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="/images/alipay.jpg" alt="Tony 支付宝">
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/04/08/前端测试工具实践/" rel="next" title="前端测试工具实践">
                <i class="fa fa-chevron-left"></i> 前端测试工具实践
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/04/08/https详解/" rel="prev" title="https详解">
                https详解 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">Tony</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives">
              
                  <span class="site-state-item-count">65</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">3</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#内容"><span class="nav-number">1.</span> <span class="nav-text">内容</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#什么是WebSocket协议"><span class="nav-number">2.</span> <span class="nav-text">什么是WebSocket协议</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#为什么要用WebSocket"><span class="nav-number">3.</span> <span class="nav-text">为什么要用WebSocket</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#了解WebSocket"><span class="nav-number">4.</span> <span class="nav-text">了解WebSocket</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#WebkSocket相关API"><span class="nav-number">5.</span> <span class="nav-text">WebkSocket相关API</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#客户端的API"><span class="nav-number">5.1.</span> <span class="nav-text">客户端的API</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#服务端的实现"><span class="nav-number">5.2.</span> <span class="nav-text">服务端的实现</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#完整例子"><span class="nav-number">6.</span> <span class="nav-text">完整例子</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; 2015 &mdash; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Tony</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Gemini</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  


  



  
  









  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  

  
  
    <script type="text/javascript" src="/lib/canvas-nest/canvas-nest.min.js"></script>
  

  
  
    <script type="text/javascript" src="/lib/three/three.min.js"></script>
  

  
  
    <script type="text/javascript" src="/lib/three/three-waves.min.js"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>